Cortex-M33 on QEMUでHelloWorld
#RP2350 #Cortex-M33 #QEMU #低レイヤ
from Adafruit Metro RP2350
QEMU上でCortex-M33向けの開発を行うには、mps2-an505ボードを利用すると良いらしい。
mps2-an505ボード上でHello Worldするサンプルアプリを作成する。
ファイル構成
code:text
.
├── main.c
├── startup.c
├── linker.ld
└── Makefile
main.c
UART0 に文字を出すだけのサンプルプログラム。AN505 の UART0 は 0x40200000 を使う。
code:main.c
#include <stdint.h>
#define UART0_BASE 0x40200000u
typedef struct {
volatile uint32_t DATA;
volatile uint32_t STATE;
volatile uint32_t CTRL;
volatile uint32_t INTSTATUS;
volatile uint32_t BAUDDIV;
} UART;
#define UART0 ((UART *)UART0_BASE)
#define UART_CTRL_TX_EN (1u << 0)
#define UART_CTRL_RX_EN (1u << 1)
static void uart_init(void) {
UART0->CTRL = UART_CTRL_TX_EN | UART_CTRL_RX_EN;
}
static void uart_putc(char c) {
UART0->DATA = (uint32_t)c;
}
static void uart_puts(const char *s) {
while (*s) {
if (*s == '\n') {
uart_putc('\r');
}
uart_putc(*s++);
}
}
int main(void) {
uart_init();
uart_puts("Hello from QEMU mps2-an505 Cortex-M33!\n");
while (1) {
}
}
startup.c
割り込みハンドラの実装と割り込みベクタの初期化。
code:startup.c
#include <stdint.h>
extern int main(void);
extern uint32_t _estack;
extern uint32_t _sidata;
extern uint32_t _sdata;
extern uint32_t _edata;
extern uint32_t _sbss;
extern uint32_t _ebss;
void Reset_Handler(void);
void Default_Handler(void) {
while (1) {
}
}
void NMI_Handler(void) __attribute__((weak, alias("Default_Handler")));
void HardFault_Handler(void) __attribute__((weak, alias("Default_Handler")));
void SVC_Handler(void) __attribute__((weak, alias("Default_Handler")));
void PendSV_Handler(void) __attribute__((weak, alias("Default_Handler")));
void SysTick_Handler(void) __attribute__((weak, alias("Default_Handler")));
__attribute__((section(".isr_vector")))
void (* const vector_table[])(void) = {
(void (*)(void))(&_estack),
Reset_Handler,
NMI_Handler,
HardFault_Handler,
Default_Handler,
Default_Handler,
Default_Handler,
0,
0,
0,
0,
SVC_Handler,
0,
0,
PendSV_Handler,
SysTick_Handler,
};
void Reset_Handler(void) {
uint32_t *src = &_sidata;
uint32_t *dst = &_sdata;
while (dst < &_edata) {
*dst++ = *src++;
}
dst = &_sbss;
while (dst < &_ebss) {
*dst++ = 0;
}
main();
while (1) {
}
}
linker.ld
code:linker.ld
ENTRY(Reset_Handler)
MEMORY
{
FLASH (rx) : ORIGIN = 0x10000000, LENGTH = 512K
RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 8M
}
_estack = ORIGIN(RAM) + LENGTH(RAM);
SECTIONS
{
.isr_vector :
{
KEEP(*(.isr_vector))
} > FLASH
.text :
{
*(.text*)
*(.rodata*)
. = ALIGN(4);
_etext = .;
} > FLASH
.data : AT(_etext)
{
. = ALIGN(4);
_sdata = .;
*(.data*)
. = ALIGN(4);
_edata = .;
} > RAM
_sidata = LOADADDR(.data);
.bss :
{
. = ALIGN(4);
_sbss = .;
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .;
} > RAM
}
Makefile
code:Makefile
CC = arm-none-eabi-gcc
OBJCOPY = arm-none-eabi-objcopy
CFLAGS = \
-mcpu=cortex-m33 \
-mthumb \
-ffreestanding \
-nostdlib \
-Wall \
-Wextra \
-O2
LDFLAGS = \
-T linker.ld \
-nostdlib \
-Wl,-Map=main.map
OBJS = startup.o main.o
all: main.elf main.bin
main.elf: $(OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
main.bin: main.elf
$(OBJCOPY) -O binary $< $@
run: main.elf
qemu-system-arm \
-machine mps2-an505 \
-cpu cortex-m33 \
-m 16M \
-nographic \
-monitor none \
-kernel main.elf
clean:
rm -f *.o *.elf *.bin *.map
ビルドと実行
code:sh
$ make
$ make run
実行結果
code:sh
$ make run
qemu-system-arm \
-machine mps2-an505 \
-cpu cortex-m33 \
-m 16M \
-nographic \
-monitor none \
-kernel main.elf
Hello from QEMU mps2-an505 Cortex-M33!
(Ctrl+c で停止)